package com.xuanyue.db.xuan.core.index;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import com.xuanyue.db.xuan.core.exception.IndexException;
import com.xuanyue.db.xuan.core.exception.SQLException;
import com.xuanyue.db.xuan.core.table.IBitIndex;
import com.xuanyue.db.xuan.core.table.IColumn;
import com.xuanyue.db.xuan.core.table.ISortElement;
import com.xuanyue.db.xuan.core.table.expr.Expr;
import com.xuanyue.db.xuan.core.table.expr.ExprValue;
import com.xuanyue.db.xuan.core.table.expr.ExprValueType;
import com.xuanyue.db.xuan.core.table.expr.SortTemplate;
import com.xuanyue.db.xuan.msg.VLAUETYPE;

/**
 * @author 解观海
 * @email  guanhaixie@sina.cn
 * @date 2020年6月23日
 * @version 0.1
 */
public class ListObject<T> implements IColumn{

	private List<IColumn> data = new ArrayList<>();
	private BitIndex mask = new BitIndex();
	private String path;
	
	public IBitIndex getMask() {
		return mask;
	}
	private  IColumn getElement(int i) {
		return data.get(i);
	}
	
	@Override
	public boolean modify(IColumn newOne,boolean cpDataFromOld) {
		@SuppressWarnings("rawtypes")
		ListObject one = (ListObject)newOne;
		
		List<IColumn> dataNew = new ArrayList<>();
		int s2 = this.data.size();
		for(int i=0,s=one.data.size();i<s;i++) {
			if(s2>i) {
				this.getElement(i).modify( one.getElement(i),cpDataFromOld );
				dataNew.add( this.getElement(i) );
			}else {
				one.getElement(i).setPath(String.format("%s/%s", path,i));
				one.getElement(i).init();
				one.getElement(i).flush(mask.getMaxId());
				dataNew.add(one.getElement(i));
			}
		}
		if(s2>one.data.size()) {//多出的部分清空
			for(int i=one.data.size();i<s2;i++) {
				File ele = new File(String.format("%s/%s", path,i));
				if(ele.exists()) {
					ele.delete();
				}
			}
		}
		return true;
	}
	
	@Override
	public void setPath(String path) {
		this.path = path;
		for(int i=0;i<data.size();i++) {
			data.get(i).setPath(String.format("%s/%s", path,i));
		}
		mask.setPath(String.format("%s/mask", path));
	}
	public ListObject(List<IColumn> columns) {
		data.addAll(columns);
	}
	
	@Override
	public void save() {
		for(int i=0;i<data.size();i++) {
			data.get(i).save();
		}
		mask.save();
	}
	
	@Override
	public void load() {
		for(int i=0;i<data.size();i++) {
			data.get(i).load();
		}
		mask.load();
	}
	
	@Override
	public void init() {
		File p = new File(path);
		if(!p.exists()) {
			p.mkdirs();
		}
		for(int i=0;i<data.size();i++) {
			data.get(i).init();
		}
		mask.init();
	}
	
	@Override
	public void set(int rowId, ExprValue value) {
		
		if(ExprValueType.NULL.is(value.getType())) {
			/**1、情况当data*/
			data.forEach(e->{
				e.set(rowId, value);
			});
			mask.set(rowId, false);
			
		}else if(ExprValueType.ARRAY.is(value.getType())) {
			List<ExprValue> vs = value.getValue();
			if(vs.size()>data.size()) {
				throw new SQLException("the array length is greater thaner the column");
			}
			for(int i=0,s=vs.size();i<s;i++) {
				data.get(i).set(rowId, vs.get(i));
			}
			if(vs.size()<data.size()) {//空占位符
				for(int i=vs.size(),s=data.size();i<s;i++) {
					data.get(i).set(rowId, ExprValue.getNULLExprValue());
				}
			}
			mask.set(rowId, true);
		}else {
			throw new SQLException("the value type mask be null or array");
		}
		mask.flush(rowId);
	}

	@Override
	public List<T> get(int rowId) {
		if(mask.get(rowId)) {
			List<T> r = new ArrayList<>();
			for(IColumn e:data) {
				@SuppressWarnings("unchecked")
				T v = (T)e.get(rowId);
				if(v==null) {
					break;
				}
				r.add(v);
			}
			return r;
		}else {
			return null;
		}
	}

	public ExprValue getExprValue(int rowId) {
		if(mask.get(rowId)) {
			List<ExprValue> r = new ArrayList<>();
			ExprValue v;
			for(IColumn e:data) {
				v = e.getExprValue(rowId);
				if(v==null) {
					break;
				}
				r.add(v);
			}
			return new ExprValue(ExprValueType.ARRAY, r);
		}else {
			return ExprValue.getNULLExprValue();
		}
		
	}
	
	@Override
	public void flush(int maxId) {
		data.forEach(d->{
			d.flush(maxId);
		});
	}

	
	@Override
	public int getDataSize() {
		int c =0;
		for(IColumn e:data) {
			c+=e.getDataSize();
		}
		return c;
	}

	public int getListSize() {
		return data.size();
	}
	
	@Override
	public List<ISortElement> getSortE(SortTemplate sortTemplate) {
		throw new IndexException(" not support the method getSortE");
	}
	@Override
	public boolean checkSortE(SortTemplate sortTemplate) {
		return sortTemplate.isType(SortTemplate.ARRAY);
	}
	@Override
	public VLAUETYPE getType() {
		return VLAUETYPE.LISTNUM;
	}

	@Override
	public void saveRow( int rowId){
		for(int i=0;i<data.size();i++) {
			data.get(i).saveRow(rowId);
		}
	}
	@Override
	public boolean checkType(ExprValue v) {
		if(ExprValueType.NULL.is(v.getType())) {
			return true;
		}else if(ExprValueType.ARRAY.is(v.getType())) {
			List<ExprValue> list = v.getValue();
			if(data.size()<list.size()) {
				return false;
			}
			for(int i=0;i<list.size();i++) {
				if(!data.get(i).checkType(list.get(i))){
					return false;
				}
			}
			return true;
		}else {
			return false;
		}
	}

	@Override
	public void exe(Expr expr, List<IBitIndex> caches) {
		ExprValue value = expr.getValue();
		/**
		 * [1:4]  表示 依次 从索引1开始（包含1）    取 索引<4的 3个元素
		 * [:4]  表示  依次 从索引0开始（包含0） 取 索引<4的 4个元素
		 * [1]  表示取索引为1的元素
		 * [:-2]  表示  依次 从索引0开始（包含0） 到 倒数 第2个元素（不包含第二个元素）
		 * [:]  表示全部元素
		 */
		int[] indexs = expr.getArryIndex();//子字符串的角标
		int start = 0;//角标默认从0开始
		int end = data.size();//角标默认到最后一个结束
		if(indexs==null) {//默认整个list
			if(ExprValueType.NULL.is( value.getType())){//检索null的记录
				caches.get(0).copyFrom(mask);
				caches.get(0).not();
				return;
			}
		}else {
			/**
			 * 无冒号时  0   表示数组索引
			 * 
			 * 有冒号时有如下4种情况：         
			 *          后面有     后面无
			 *    前面有         1     2
			 *    前面无         3     4
			 * 
			 * 1 :   num:num
			 * 2:    num:
			 * 3:       :num
			 * 4:       :
			 * 
			 */
			if(indexs[1]==1) {
				start = (indexs[0]<0?indexs[0]+data.size():indexs[0]);
				end   = (indexs[2]<0?indexs[2]+data.size():indexs[2]);
			}else if(indexs[1]==2) {
				start = (indexs[0]<0?indexs[0]+data.size():indexs[0]);
			}else if(indexs[1]==3) {
				end   = (indexs[2]<0?indexs[2]+data.size():indexs[2]);
			}else if(indexs[1]==0){//索引无冒号 索引蜕变成单个元素
				start = (indexs[0]<0?indexs[0]+data.size():indexs[0]);
				data.get(start).exe(new Expr(expr.getOp(), String.format("%s[%s]", expr.getCname(),indexs[0]  ), null, null, value),caches);
				return;
			}
		}
		if( start>=end||start<0||end<0|| start>=data.size()||end>data.size()) {
			throw new SQLException(String.format("%s[%s:%s] out of index ",expr.getCname(),start,end ));
		}
		if(ExprValueType.ARRAY.is( value.getType())) {
			
			List<ExprValue> list = value.getValue();
			if(list.size()==0) {
				throw new SQLException("expr right: arrray of length is zero ");
			}
			/**
			 * 逻辑表达式中左侧的数组长度
			 */
			int dx= end-start;
			if("=".equals(expr.getOp())) {
				if(dx!=list.size()) {// 表达式两侧数组  长度不相等   所以  表达式一定不成立   矛盾式
					caches.get(0).setAll(false);
					return ;
				}else {//长度相等时， 每个元素都相等才能相等。
					List<IBitIndex> subCaches = caches.subList(1, caches.size());
					Expr ele = new Expr();
					ele.setOp("=");
					IBitIndex r = caches.get(0);
					IBitIndex sub = caches.get(1);
					r.setAll(true);
					for(int i=0;i<dx;i++) {
						ele.setValue(list.get(i));
						data.get(i+start).exe(ele, subCaches);
						r.and(sub);
					}
					return;
				}
			}else if("!=".equals(expr.getOp())) {
				if(dx!=list.size()) {// 表达式两侧数组  长度不相等   所以   表达式一定成立  永真式
					caches.get(0).setAll(true);
					return;
				}else {//表达式两侧数组  长度相等    先求 相等的情况，然后取反
					List<IBitIndex> subCaches = caches.subList(1, caches.size());
					Expr ele = new Expr();
					ele.setOp("=");
					IBitIndex r = caches.get(0);
					IBitIndex sub = caches.get(1);
					r.setAll(true);
					
					for(int i=0;i<dx;i++) {
						ele.setValue(list.get(i));
						data.get(i+start).exe(ele, subCaches);
						r.and(sub);
					}
					r.not();//取反
					return;
				}
			}else if(">".equals(expr.getOp())||">=".equals(expr.getOp())||
					"<".equals(expr.getOp())||"<=".equals(expr.getOp())
					) {
				Expr ele = new Expr();//循环体重的逻辑表达式
				/**最终结果
				 * 从start开始，每个元素的逻辑判断结果 累积等到
				 */
				IBitIndex r = caches.get(0);
				r.setAll(false);
				/**
				 * 记录从一开始到循环体 之前 所有元素相等的记录
				 */
				IBitIndex eq = caches.get(1);
				eq.setAll(true);
				/**
				 * 每次循环的的逻辑判断结果
				 */
				IBitIndex tmp = caches.get(2);
				/**
				 * 每次循环进行逻辑判断的计算资源
				 */
				List<IBitIndex> subCaches = caches.subList(2, caches.size());
				
				/**
				 * 超界时，表达式右侧的数据为null
				 */
				ExprValue NULL = new ExprValue();
				NULL.setType(ExprValueType.NULL);
				String eo = expr.getOp().startsWith(">")?">":"<" ;
				ExprValue ev = null;
				for(int i=0,size=list.size();i<dx;i++) {
					ev= (i<size?list.get(i): NULL);
					ele.setValue(ev);
					if(i<dx) {//数据列  没有越界
						ele.setOp( eo );
						data.get(i+start).exe(ele, subCaches);
						r.orByinnerAnd(eq, tmp);
						ele.setOp("=");
						data.get(i+start).exe(ele, subCaches);
						eq.and(tmp);
					}else {
						//数据列超界  元素比较时 认为表中超界的元素为NULL
						if(">".equals(expr.getOp())) {
							// 从start到上一个元素  列数据大于 表达式右值的记录报错在   r 中
							// 从当前元素向后  都为  矛盾式
							return;
						}else if(">=".equals(expr.getOp())) {
							if(!ExprValueType.NULL.is(ev.getType())) {
								// 当前的列数据 元素为 NULL  当前表达式右值记录不为空   所以当前和后续元素比较都为   矛盾式
								return;
							}else {
								// 当前的列数据 元素为 NULL  当前表达式右值记录为空   所以  当前元素 相等为 永真式
								continue;
							}
						}else if("<".equals(expr.getOp())) {
							if(ExprValueType.NULL.is(ev.getType())) {
								// 当前的列数据 元素为 NULL  当前表达式右值记录为空   所以  当前元素 相等为 永真式
								continue;
							}else {// 当前的列数据 元素为 NULL  当前表达式右值记录不为空   所以  当前元素 的比较为 永真式
								r.or(eq);
								return;
							}
						}else if("<=".equals(expr.getOp())) {
							if(ExprValueType.NULL.is(ev.getType())) {
								// 当前的列数据 元素为 NULL  当前表达式右值记录为空   所以  当前元素 相等为 永真式
								continue;
							}else {
								// 当前的列数据 元素为 NULL  当前表达式右值记录不为空   所以  当前元素 的比较为 矛盾式
								r.or(eq);
								return;
							}
						}
					}
				}
				if("<=".equals(expr.getOp())||">=".equals(expr.getOp())) {
					r.or(eq);//最终结果加入相等的情况
				}
			}else {
				throw new SQLException("expr op is not support :"+expr.getOp());
			}
		}else {
			throw new SQLException("expr right value ERROR :"+expr.getCname());
		}
	}
	@Override
	public int checkAndContSource(Expr expr) {
		ExprValue value = expr.getValue();
		
		int start = 0;
		int end = data.size();
		
		int[] indexs = expr.getArryIndex();
		if(indexs==null) {
			if(ExprValueType.NULL.is( value.getType())){
				return 1;
			}
		}else {
			
			
			/**
			 * 无冒号时  0   表示数组索引
			 * 
			 * 有冒号时有如下4种情况：         
			 *          后面有     后面无
			 *    前面有         1     2
			 *    前面无         3     4
			 * 
			 * 1 :   num:num
			 * 2:    num:
			 * 3:       :num
			 * 4:       :
			 * 
			 */
			if(indexs[1]==1) {
				start = (indexs[0]<0?indexs[0]+data.size():indexs[0]);
				end   = (indexs[2]<0?indexs[2]+data.size():indexs[2]);
			}else if(indexs[1]==2) {
				start = (indexs[0]<0?indexs[0]+data.size():indexs[0]);
			}else if(indexs[1]==3) {
				end   = (indexs[2]<0?indexs[2]+data.size():indexs[2]);
			}else if(indexs[1]==0){//索引无冒号 索引蜕变成单个元素
				start = (indexs[0]<0?indexs[0]+data.size():indexs[0]);
				if(start>=data.size()||start<0) {//索引越界
					return 0;
				}
				return data.get(start).checkAndContSource(new Expr(expr.getOp(), String.format("%s[%s]", expr.getCname(),indexs[0]  ), null, null, value));
			}
		}
		if( start>=end||start<0||end<0|| start>=data.size()||end>=data.size()) {
			return 0;
		}
		if(ExprValueType.ARRAY.is( value.getType())) {
			List<ExprValue> list = value.getValue();
			if(list.size()==0) {
				return 0;
			}
			int dx= end-start;
			if("=".equals(expr.getOp())) {
				int s = data.get(start).checkAndContSource( new Expr("=", String.format("%s[%s]", expr.getCname(),start), null, null, list.get(0))  );
				if(s==0) {
					return 0;
				}
				if(dx!=list.size()) {
					return 1;
				}else {
					return s+1;
				}
			}else if("!=".equals(expr.getOp())) {
				int s = data.get(start).checkAndContSource( new Expr("=", String.format("%s[%s]", expr.getCname(),start), null, null, list.get(0))  );
				if(s==0) {
					return 0;
				}
				if(dx!=list.size()) {
					return 1;
				}else {
					return s+1;
				}
			}else if(">".equals(expr.getOp())||">=".equals(expr.getOp())||
					"<".equals(expr.getOp())||"<=".equals(expr.getOp())
					) {
				int s = data.get(start).checkAndContSource( new Expr("=", String.format("%s[%s]", expr.getCname(),start), null, null, list.get(0))  );
				if(s==0) {
					return 0;
				}
				int s2 = data.get(start).checkAndContSource( new Expr( expr.getOp().substring(0, 1) , String.format("%s[%s]", expr.getCname(),start), null, null, list.get(0))  );
				if(s2==0) {
					return 0;
				}
				if(s<s2) {
					s=s2;
				}
				return 2+(s<s2?s2:s );
			}else {
				return 0;
			}
		}else {
			return 0;
		}
	}
}
